package graph_viewer.structure.clustering;

import java.util.*;

import graph_viewer.animator.*;
import graph_viewer.app_exception.*;
import graph_viewer.canvas.*;
import graph_viewer.layout.*;
import graph_viewer.util.*;
import graph_viewer.structure.*;
/**
 * define tree node
 */
public class Create_Pseudo_Cluster_Strategy extends Graph_Basic_Cluster_Strategy{	
	public Create_Pseudo_Cluster_Strategy(){
		Debug.println( "\tCreate_Pseudo_Cluster_Strategy created!", 5 );
	}

	////  create a pseudo cluster to contain closed children in this cluster.	
	public void do_cluster_action( Graph a_graph, Node node, Graph_Canvas a_graph_canvas  ){	
		Node_Position position_without_pseudo_cluster	= new Node_Position( node.get_position() );

		int
			x_center_without_pseudo_cluster	= position_without_pseudo_cluster.get_x_center(),
			y_center_without_pseudo_cluster	= position_without_pseudo_cluster.get_y_center();

		Debug.println( "\tCreate_Pseudo_Cluster_Strategy do_cluster_action on:" + node + " at " + position_without_pseudo_cluster, 53 );

		if ( node.is_root() ){
			return ;//do nothing
		}
		
		if ( Clustering_Util.has_pseudo_child( node ) ){
			Debug.println( "\tDo append_to_pseudo_child:" + node, 25 );
			append_to_pseudo_child( a_graph, node, a_graph_canvas );
		}else{
			Debug.println( "\tDo add_a_pseudo_child:" + node, 25 );
			add_a_pseudo_child( a_graph, node, a_graph_canvas );
		}
					
		// when a new psuedo-cluster is created or some leaf-clusters added to a existing psudo-cluster,
		// the center of the parent cluster might change. Consquently, the orthogonal odering will be destoried.
		// It is not necessary for other springs than ODNLS.	
		
		Node_Position position_with_pseudo_cluster	= new Node_Position( node.get_position() );
		
		position_with_pseudo_cluster.set_x_center( x_center_without_pseudo_cluster );
		position_with_pseudo_cluster.set_y_center( y_center_without_pseudo_cluster );



		Debug.println( "\tmove:" + node + " back to: " + position_without_pseudo_cluster + " from: " + position_with_pseudo_cluster, 53 );
		Layout_Util.move_super_cluster( a_graph, node, position_with_pseudo_cluster );

		Debug.println( "\tAfter move back:" + node + " at: " + node.get_position(), 53 );
		
		new ODNLS_Impl().do_layout_action( node, a_graph_canvas, new Spring_Metrics() );
		

		node.set_is_closed( false );
	}

	public ArrayList build_pre_clustering_animation_metrics( Graph_Canvas a_graph_canvas, String node_label ){		
		ArrayList 	a_m ;
		
		Graph		the_graph	= a_graph_canvas.get_graph();
		Node		the_node		= the_graph.search( node_label );

		if ( Clustering_Util.has_pseudo_child( the_node ) ){
			a_m	= append_to_pseudo_child_metrics( the_graph, the_node );
		}else{
			a_m	= add_a_pseudo_child_metrics( the_graph, the_node, a_graph_canvas );
		}

		return a_m;
	}

	public ArrayList build_post_clustering_animation_metrics( Graph_Canvas a_graph_canvas, String node_label ){

		Debug.println( "Create_Pseudo_Cluster_Strategy.build_post_clustering_animation_metrics...!", 26 );
		ArrayList animator_metrics	= new ArrayList();
		
		Graph		the_graph	= a_graph_canvas.get_graph();
		Node		the_node		= the_graph.search( node_label );
		ArrayList		children		= the_node.get_children();
		
		ArrayList children_position_bf_spring	= Node_Position_Helper.clone_nodes_position( children );
		//do spring to the node
		Layout spring	 = a_graph_canvas.get_layout();		

		int[] orignal_center	= the_node.get_position().find_center();
		
		Spring_Metrics	 sm	= new Spring_Metrics( false, true );

		Debug.println( "Create_Pseudo_Cluster_Strategy do_layout_action for " + node_label, 26 );
		spring.do_layout_action(  the_node, a_graph_canvas, sm);
		//spring.fixed_external_clusters_spring_action( the_node, the_graph );

		int[] current_center	= the_node.get_position().find_center();
		
		Layout_Util.move_node_to_another_center( the_graph, the_node.get_label(), current_center, orignal_center );		
		
		ArrayList children_position_aft_spring	= Node_Position_Helper.clone_nodes_position( children );

		for ( int i = 0; i < children.size(); i++ ){
			Node child	= (Node)children.get( i );

			Node_Position
				the_child_position_bf_open	= (Node_Position)children_position_bf_spring.get(i),
				the_child_position_aft_open	= (Node_Position)children_position_aft_spring.get(i);

			child.set_position( the_child_position_bf_open );
			
			Animator_Metrics a_m = new Animator_Metrics(		new Motion_Animator(),
														child.get_label(),
														the_child_position_bf_open,		
														the_child_position_aft_open																				
													);
			animator_metrics.add( a_m );
		}

		return animator_metrics;
	}
	
	public String toString(){
		return "CREATE_STRATEGY";
	}
	
	//==================================================
	// private utils
	//==================================================
	//append all demagnified children to the existing pseudo child
	private void append_to_pseudo_child( Graph a_graph, Node node, Graph_Canvas a_graph_canvas ){
		ArrayList all_demagnified_children = find_all_demagnified_children( node );
		
		Node psuedo_cluster	= Clustering_Util.find_psuedo_child( node );

		if ( psuedo_cluster == null ){
			throw new App_Exception( "When append to pseudo child, not psuedo child found!" );
		}

		//set all_demagnified_children closed
		//set all_demagnified_children as psuedo node's child		
		//set psuedo as all_demagnified_children node's parent
		//delete all_demagnified_children from node's child

		for ( Iterator _i = all_demagnified_children.iterator(); _i.hasNext(); ){
			Node child	= (Node)_i.next();
			child.set_parent( psuedo_cluster );
			child.set_is_closed( true );
			child.set_is_labelled( true );
			child.set_position( null );
			node.delete_child( child );				
		}

		psuedo_cluster.get_children().addAll( all_demagnified_children );		
		
		if ( node.get_children().size() == 1 ){//after append to psuedo node, there is only one psuedo child of the node, so close the node
			node.set_is_closed( true );
			Clustering_Util.remove_pseudo_child( a_graph, node );
			Node_Position_Helper.set_leaf_cluster_size( node, a_graph_canvas.getGraphics() );
		}
	}
	
	//create a new pseudo-cluster
	private void add_a_pseudo_child( Graph a_graph, Node node, Graph_Canvas a_graph_canvas ){

		//create the new node:
		/*to-do:
			label: empty
			set_children: all the closed_children
			all_closed_chilren: set_parent( pseudo_cluster );
			set_parent: node
			set_is_psuedo: true
			set_position
			edge:???//
			

		a_graph.get_cluster_tree. add(pseudo_cluster);
		node.remove_children
		*/
		
		Node psuedo_cluster = create_a_psuedo_child( node, a_graph_canvas );

		ArrayList all_demagnified_children = find_all_demagnified_children( node );		
		psuedo_cluster.set_children( all_demagnified_children );				

		//psuedo_cluster should be added infront of it children, in order to get referrenced when copy to a new tree.
		a_graph.add_node( psuedo_cluster );//node add psuedo_cluster as a child here
		
		for ( Iterator _i = all_demagnified_children.iterator(); _i.hasNext(); ){
			Node child	= (Node)_i.next();
			child.set_parent( psuedo_cluster );
			child.set_is_closed( true );
			child.set_is_labelled( true );
			child.set_position( null );
			node.delete_child( child );				
		}				
	}

	//create animation metrics for add a_psuedo_metrics
	private ArrayList add_a_pseudo_child_metrics( Graph a_graph, Node node, Graph_Canvas a_graph_canvas ){	
		Debug.println( "Building add_a_pseudo_child_metrics...", 3 );
		ArrayList animator_metrics	 = new ArrayList();

		Node psuedo_cluster = create_a_psuedo_child( node, a_graph_canvas );
		
		Node_Position	dest_position	= new Node_Position( psuedo_cluster.get_position() );

		ArrayList all_demagnified_children = find_all_demagnified_children( node );		
		
		for ( Iterator _i = all_demagnified_children.iterator(); _i.hasNext(); ){
			Node demg_child	= (Node)_i.next();
			
			demg_child.set_is_labelled( false );

			Animator_Metrics	a_m	= new Animator_Metrics(	
									new Motion_Animator(),
									demg_child.get_label(),
									demg_child.get_position(),
									dest_position
								);

			animator_metrics.add( a_m );
		}

		return animator_metrics;
	}

	private ArrayList append_to_pseudo_child_metrics( Graph a_graph, Node node ){
		Debug.println( "Building append_to_pseudo_child_metrics...", 3 );
		ArrayList animator_metrics	 = new ArrayList();

		Node psuedo_cluster = Clustering_Util.find_psuedo_child( node );
		
		Node_Position	dest_position	= new Node_Position( psuedo_cluster.get_position() );

		ArrayList all_demagnified_children = find_all_demagnified_children( node );		
		
		for ( Iterator _i = all_demagnified_children.iterator(); _i.hasNext(); ){
			Node demg_child	= (Node)_i.next();
			
			demg_child.set_is_labelled( false );

			Animator_Metrics	a_m	= new Animator_Metrics(
									new Motion_Animator(),
									demg_child.get_label(),
									demg_child.get_position(),
									dest_position
								);
			animator_metrics.add( a_m );
		}

		return animator_metrics;
	}


} 